#include "Oled_I2C.h"
#include "Oled_Font.h"

#define OLED_I2C_TIMEOUT 10000

uint8_t OLED_GRAM[144][8];

void Oled_WR_Byte(uint8_t dat,uint8_t mode);

void Oled_Init() {
  LL_I2C_Enable(I2C2);
  LL_mDelay(500);
  Oled_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
	Oled_WR_Byte(0x00,OLED_CMD);//---set low column address
	Oled_WR_Byte(0x10,OLED_CMD);//---set high column address
	Oled_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
	Oled_WR_Byte(0x81,OLED_CMD);//--set contrast control register
	Oled_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current Brightness
	Oled_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
	Oled_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
	Oled_WR_Byte(0xA6,OLED_CMD);//--set normal display
	Oled_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	Oled_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
	Oled_WR_Byte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
	Oled_WR_Byte(0x00,OLED_CMD);//-not offset
	Oled_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
	Oled_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
	Oled_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
	Oled_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	Oled_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
	Oled_WR_Byte(0x12,OLED_CMD);
	Oled_WR_Byte(0xDB,OLED_CMD);//--set vcomh
	Oled_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
	Oled_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
	Oled_WR_Byte(0x02,OLED_CMD);//
	Oled_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
	Oled_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
	Oled_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
	Oled_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) 
	Oled_Clear();
	Oled_WR_Byte(0xAF,OLED_CMD);
  
  LL_mDelay(100);
  Oled_ShowString(10, 10, "init", 16, 1);
  Oled_Refresh();
  LL_mDelay(1000);
  Oled_Clear();
}

void Oled_Clear(void)
{
	uint8_t i,n;
	for(i=0;i<8;i++)
	{
	   for(n=0;n<128;n++)
			{
			 OLED_GRAM[n][i]=0;//清除所有数据
			}
  }
	Oled_Refresh();//更新显示
}

void Oled_Refresh(void)
{
	uint8_t i,n;
	for(i=0;i<8;i++)
	{
		Oled_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
		Oled_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址
		Oled_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址
    
    // 批量传输数据
		LL_I2C_GenerateStartCondition(I2C2);
    while (!LL_I2C_IsActiveFlag_SB(I2C2)) {}
    LL_I2C_TransmitData8(I2C2, 0x78);
    while (!LL_I2C_IsActiveFlag_ADDR(I2C2)) {}
    LL_I2C_ClearFlag_ADDR(I2C2);
		LL_I2C_TransmitData8(I2C2, 0x40);
    while (!LL_I2C_IsActiveFlag_TXE(I2C2)) {}
		for(n=0;n<128;n++)
		{
			LL_I2C_TransmitData8(I2C2, OLED_GRAM[n][i]);
      while (!LL_I2C_IsActiveFlag_TXE(I2C2)) {}
		}
		LL_I2C_GenerateStopCondition(I2C2);
  }
}

//画点 
//x:0~127
//y:0~63
//t:1 填充 0,清空	
void Oled_DrawPoint(uint8_t x,uint8_t y,uint8_t t)
{
	uint8_t i,m,n;
	i=y/8;
	m=y%8;
	n=1<<m;
	if(t){OLED_GRAM[x][i]|=n;}
	else
	{
		OLED_GRAM[x][i]=~OLED_GRAM[x][i];
		OLED_GRAM[x][i]|=n;
		OLED_GRAM[x][i]=~OLED_GRAM[x][i];
	}
}


//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//size1:选择字体 6x8/6x12/8x16/12x24
//mode:0,反色显示;1,正常显示
void Oled_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1,uint8_t mode)
{
	uint8_t i,m,temp,size2,chr1;
	uint8_t x0=x,y0=y;
	if(size1==8)size2=6;
	else size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数
	chr1=chr-' ';  //计算偏移后的值
	for(i=0;i<size2;i++)
	{
		if(size1==8)
			  {temp=asc2_0806[chr1][i];} //调用0806字体
		else if(size1==12)
        {temp=asc2_1206[chr1][i];} //调用1206字体
		else if(size1==16)
        {temp=asc2_1608[chr1][i];} //调用1608字体
		else if(size1==24)
        {temp=asc2_2412[chr1][i];} //调用2412字体
		else return;
		for(m=0;m<8;m++)
		{
			if(temp&0x01)Oled_DrawPoint(x,y,mode);
			else Oled_DrawPoint(x,y,!mode);
			temp>>=1;
			y++;
		}
		x++;
		if((size1!=8)&&((x-x0)==size1/2))
		{x=x0;y0=y0+8;}
		y=y0;
  }
}

//m^n
uint32_t OLED_Pow(uint8_t m,uint8_t n)
{
	uint32_t result=1;
	while(n--)
	{
	  result*=m;
	}
	return result;
}

//显示数字
//x,y :起点坐标
//num :要显示的数字
//len :数字的位数
//size:字体大小
//mode:0,反色显示;1,正常显示
void Oled_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size1,uint8_t mode)
{
	uint8_t t,temp,m=0;
	if(size1==8)m=2;
	for(t=0;t<len;t++)
	{
		temp=(num/OLED_Pow(10,len-t-1))%10;
			if(temp==0)
			{
				Oled_ShowChar(x+(size1/2+m)*t,y,'0',size1,mode);
      }
			else 
			{
			  Oled_ShowChar(x+(size1/2+m)*t,y,temp+'0',size1,mode);
			}
  }
}

//显示字符串
//x,y:起点坐标  
//size1:字体大小 
//*chr:字符串起始地址 
//mode:0,反色显示;1,正常显示
void Oled_ShowString(uint8_t x,uint8_t y,char *chr,uint8_t size1,uint8_t mode)
{
	while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
	{
		Oled_ShowChar(x,y,*chr,size1,mode);
		if(size1==8)x+=6;
		else x+=size1/2;
		chr++;
  }
}


void Oled_WR_Byte(uint8_t dat, uint8_t mode)
  {
  // Wait until bus is free
  while (LL_I2C_IsActiveFlag_BUSY(I2C2)) {}
  // 生成起始条件
  LL_I2C_GenerateStartCondition(I2C2);
  while(!LL_I2C_IsActiveFlag_SB(I2C2)) {};
  
  // 发送设备地址（0x78 << 1 = 0xF0）
  LL_I2C_TransmitData8(I2C2, 0x78);
  while (!LL_I2C_IsActiveFlag_ADDR(I2C2)) {};
  LL_I2C_ClearFlag_ADDR(I2C2);
  if(mode){
    LL_I2C_TransmitData8(I2C2, 0x40);
    while(!LL_I2C_IsActiveFlag_TXE(I2C2)) {};
  }
  else{
    LL_I2C_TransmitData8(I2C2, 0x00);
    while(!LL_I2C_IsActiveFlag_TXE(I2C2)) {};
  }
	LL_I2C_TransmitData8(I2C2, dat);
  while(!LL_I2C_IsActiveFlag_TXE(I2C2)) {};
	LL_I2C_GenerateStopCondition(I2C2);
}
